﻿namespace JumpstartApp.Helpers
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;

    using Microsoft.Live;

    using Windows.Storage;

    public static class SkyDriveHelper
    {
        #region Static Fields

        private static LiveConnectSession session;

        #endregion

        #region Public Methods and Operators

        public static async Task<SkyDriveFolderInfo> CreateFolder(
            string folderName, string parentFolder = "/me/skydrive")
        {
            try
            {
                if (session == null)
                {
                    await Login();
                }
                var folderData = new Dictionary<string, object> { { "name", folderName } };
                var liveClient = new LiveConnectClient(session);
                LiveOperationResult operationResult = await liveClient.PostAsync(parentFolder, folderData);
                dynamic result = operationResult.Result;
                return new SkyDriveFolderInfo(result);
            }
            catch (LiveConnectException exception)
            {
                throw new Exception("Unable to create folder " + folderName, exception);
            }
        }

        public static async Task<bool> DownloadFile(string skyDriveFileId, StorageFile destinationFile)
        {
            try
            {
                if (destinationFile != null)
                {
                    if (session == null)
                    {
                        await Login();
                    }

                    var liveClient = new LiveConnectClient(session);
                    LiveDownloadOperationResult result =
                        await liveClient.BackgroundDownloadAsync(skyDriveFileId, destinationFile);
                    return true;
                }

                return false;
            }
            catch (LiveConnectException exception)
            {
                throw new Exception("Unable to download file " + skyDriveFileId, exception);
            }
        }

        public static async Task<SkyDriveFileInfo> GetFileIfExists(string fileName, string parentFolder = "")
        {
            IList<SkyDriveFileInfo> files = string.IsNullOrWhiteSpace(parentFolder)
                                                ? await GetFiles()
                                                : await GetFiles(parentFolder);
            return files.FirstOrDefault(f => f.Name == fileName);
        }

        public static async Task<IList<SkyDriveFileInfo>> GetFiles(string folderName = "/me/skydrive")
        {
            try
            {
                if (session == null)
                {
                    await Login();
                }

                var liveClient = new LiveConnectClient(session);
                LiveOperationResult operationResult = await liveClient.GetAsync(folderName + "/files");
                dynamic result = operationResult.Result;
                var results = new List<SkyDriveFileInfo>();
                foreach (dynamic files in result.data)
                {
                    results.Add(new SkyDriveFileInfo(files));
                }
                return results;
            }
            catch (LiveConnectException exception)
            {
                throw new Exception("Unable to read files", exception);
            }
        }

        public static async Task<SkyDriveFolderInfo> GetFolderIfExists(string folderName, string parentFolder = "")
        {
            IList<SkyDriveFolderInfo> folders = string.IsNullOrWhiteSpace(parentFolder)
                                                    ? await GetFolders()
                                                    : await GetFolders(parentFolder);
            return folders.FirstOrDefault(f => f.Name == folderName);
        }

        public static async Task<IList<SkyDriveFolderInfo>> GetFolders(string folderName = "/me/skydrive")
        {
            try
            {
                if (session == null)
                {
                    await Login();
                }

                var liveClient = new LiveConnectClient(session);
                LiveOperationResult operationResult = await liveClient.GetAsync(folderName + "/files?filter=folders");
                dynamic result = operationResult.Result;
                var results = new List<SkyDriveFolderInfo>();
                foreach (dynamic folder in result.data)
                {
                    results.Add(new SkyDriveFolderInfo(folder));
                }
                return results;
            }
            catch (LiveConnectException exception)
            {
                throw new Exception("Unable to read folders", exception);
            }
        }

        public static async Task<SkyDriveFolderInfo> GetOrCreateApplicationDataFolder(string appName)
        {
            // Follows guidance on application storage on SkyDrive found in this blog post:
            // http://blogs.windows.com/skydrive/b/skydrive/archive/2012/09/10/attachments-me-connecting-skydrive-with-gmail-and-tips-for-other-skydrive-developers.aspx

            // All application data should be contained in this folder
            SkyDriveFolderInfo appDataFolderInfo = await GetFolderIfExists("ApplicationData");
            if (appDataFolderInfo == null)
            {
                appDataFolderInfo = await CreateFolder("ApplicationData");
            }

            // appName should be of the format "Application Name (Publisher)", i.e. "Windows 8 Jumpstart (DPEUSW)"
            SkyDriveFolderInfo appFolderInfo = await GetFolderIfExists(appName, appDataFolderInfo.Id);
            if (appFolderInfo == null)
            {
                appFolderInfo = await CreateFolder(appName, appDataFolderInfo.Id);
            }

            return appFolderInfo;
        }

        public static async Task<SkyDriveFolderInfo> ReadFolderOrFileInformation(string itemId)
        {
            try
            {
                if (session == null)
                {
                    await Login();
                }
                var liveClient = new LiveConnectClient(session);
                LiveOperationResult operationResult = await liveClient.GetAsync(itemId);
                dynamic result = operationResult.Result;


                return new SkyDriveFolderInfo(result);
            }
            catch (LiveConnectException exception)
            {
                throw new Exception("Unable to read Folder Information " + itemId, exception);
            }
        }

        public static async Task<SkyDriveFolderInfo> UploadFile(
            StorageFile sourceFile, string skyDriveFileName, string skyDriveParentFolder)
        {
            try
            {
                if (sourceFile != null)
                {
                    if (session == null)
                    {
                        await Login();
                    }
                    var liveClient = new LiveConnectClient(session);
                    LiveOperationResult operationResult =
                        await
                        liveClient.BackgroundUploadAsync(
                            skyDriveParentFolder, skyDriveFileName, sourceFile, OverwriteOption.Overwrite);
                    dynamic result = operationResult.Result;


                    return new SkyDriveFolderInfo(result);
                }

                return null;
            }
            catch (LiveConnectException exception)
            {
                throw new Exception("Unable to upload file to " + skyDriveFileName, exception);
            }
        }

        #endregion

        #region Methods

        private static async Task Login()
        {
            await LiveSdk.LoginAsync(false);
            session = LiveSdk.LoginResult.Session;
        }

        #endregion

        public class SkyDriveFileInfo : SkyDriveFolderInfo
        {
            #region Constructors and Destructors

            public SkyDriveFileInfo(dynamic result)
            {
                this.Initialize(result);
                this.DownloadPath = result.source;
            }

            #endregion

            #region Public Properties

            public string DownloadPath { get; protected set; }

            #endregion
        }

        public class SkyDriveFolderInfo
        {
            #region Constructors and Destructors

            public SkyDriveFolderInfo(dynamic result)
            {
                this.Initialize(result);
            }

            protected SkyDriveFolderInfo()
            {
            }

            #endregion

            #region Public Properties

            public string Description { get; protected set; }

            public string Id { get; protected set; }

            public string Link { get; protected set; }

            public string Name { get; protected set; }

            public string Type { get; protected set; }

            public string UploadPath { get; protected set; }

            #endregion

            #region Methods

            protected void Initialize(dynamic result)
            {
                this.Id = result.id;
                this.Name = result.name;
                this.UploadPath = result.upload_location;
                this.Description = result.description;
                this.Link = result.link;
                this.Type = result.type;
            }

            #endregion
        }
    }
}